#define _CRT_SECURE_NO_WARNINGS 1

// 函数重载

// 其实就是一词多义，国足“谁也赢不过”、乒乓球“谁也赢不过”

// 函数重载：是函数的一种特殊情况，C++允许在 同一作用域 中声明几个功能类似的 同名函数
// 这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同，
// 常用来处理实现 功能类似 数据类型不同 的问题。

//#include <iostream>
//using namespace std;
//
//// 不同作用域，可以重名
//namespace tan1 {
//	void Swap(int* pa, int* pb)
//	{
//		cout << "void Swap(int* pa, int* pb)" << endl;
//	}
//}
//
//namespace tan2 {
//	void Swap(double* pa, double* pb)
//	{
//		cout << "void Swap(double* pa, double* pb)" << endl;
//	}
//}
//
//// 参数个数不同
////void f()
////{
////	cout << "f()" << endl;
////}
////void f(int a)
////{
//// cout << "f(int a)" << endl;
////}
//
//// 参数类型顺序不同
////void f(int a, char b)
////{
////	cout << "f(int a,char b)" << endl;
////}
////void f(char b, int a)
////{
////	cout << "f(char b, int a)" << endl;
////}
//
//// 下面两个也构成重载，符合 参数数量不同 的必要条件
//// 但是不要那么使用，会有歧义 f()； 就比较尴尬
////void f()
////{
////	cout << "f()" << endl;
////}
////
////void f(int a = 10)
////{
////	cout << "f(int a)" << endl;
////}
//
//using namespace tan1;
//using namespace tan2;
//// 它们两依旧是OK，但不是重载关系
//// 还是在各自的作用域，只是在自己的菜地插了一块牌子，菜还是该谁的就谁的
//// “展开就放在全局了”，这个想法是错的
//
//// 返回值不同不构成重载
//// 或许以下函数你会觉得一个有返回值一个没有
//// 编译器应该很轻松的分辨出来要调用那个
//// 但是假如单走一个 f(); 语句呢？
//// 就不好辨认了
///*
//int f()
//{
//	cout << "f()" << endl;
//	return;
//}
//
//void f()
//{
//	cout << "f()" << endl;
//}
//*/
//
//int main()
//{
//	int a = 1, b = 2;
//	double c = 1.0, d = 2.0;
//
//	Swap(&a, &b);
//	Swap(&c, &d);
//
//	f();
//	f(1);
//
//	f(1, 'c');
//	f('c', 1);
//
//	return 0;
//}

// 我们可以来思考一下为什么 C++ 可以函数重载，而 C 不行？
// 这就要回到我们当时学C语言的 预处理 和 编译 了

// 预处理完后，其实是 单线 的
// Stack.h Stack.cpp Test.cpp
// 预处理：展开头文件 / 宏替换 / 软件编译......

// Stack.i Test.i
// 编译：检查语法，生成汇编代码

// Stack.s Test.s
// 汇编：把汇编代码转成二进制机器码

// Stack.o Test.o
// 链接：生成可执行程序
// xxx.exe

// 函数有一堆要执行的指令
// 而函数的地址本质上就是第一句指令的地址
// 有定义的才有地址，在链接前都是单线的，不交互

// 符号表就是 函数名 和 地址 的映射
// 链接的时候，直接用原本的函数去查找，那么就不支持重载，C语言 就是这样
// 而 C++ 会根据参数的个数、类型、顺序进行修饰，在链接的时候可以区分

// VS环境下的函数修饰规则极其复杂
// 函数名字修饰规则
// https://blog.csdn.net/lioncolumn/article/details/10376891
// 不同平台的修饰规则可能不同，但是一定是有加修饰的规则


// 引用
// 引用不是新定义一个变量，而是给已存在变量取了一个别名
// 编译器不会为引用变量开辟内存空间，它和它引用的变量共用同一块内存空间。

// “李逵” 就是 “铁牛” 就是 “黑旋风”

//#include <iostream>
//using namespace std;
//
//int main()
//{
//	int a = 0;
//
//	// 引用类型必须和引用实体是同种类型的
//	// 引用可以再引用，本质上都是运用同一块内存空间
//
//	int& b = a;
//	int& c = b;
//	int& d = c;
//
//	d++;
//	return 0;
//}

// 引用的价值

//#include <iostream>
//using namespace std;
//
//// 其实，引用这个概念的作用与指针很大概念是重合的
//void swap(int* pa, int* pb)
//{
//	int tmp = *pa;
//	*pa = *pb;
//	*pb = tmp;
//}
//
//void swap(int& a, int& b)
//{
//	int tmp = a;
//	a = b;
//	b = tmp;
//}
//
//int main()
//{
//	int x = 0, y = 1;
//
//	cout << x << " " << y << endl; // 0 1
//	swap(&x, &y);
//
//	cout << x << " " << y << endl; // 1 0
//
//	swap(x, y);
//	cout << x << " " << y << endl; // 0 1
//
//	return 0;
//}

// 引用特性
// 1. 引用在定义时必须初始化
// 2. 一个变量可以有多个引用
// 3. 引用一旦引用一个实体，再不能引用其他实体

// 祖师爷本杰明在试图让C语言变得简单
// 说不定搞着搞着就成了新的语言，结果有的特性还更复杂
// 事与愿违是常态~

//int main()
//{
//	int x = 0;
//	int& y = x;
//
//	int z = 1;
//
//	y = z; // z 赋值给 y，而不是 y 变成 z 的别名
// 
//	return 0;
//}

//int main()
//{
//	int x = 0;
//	int& y = x;
//	const int& z = x; // right，权限的缩小
//	y++; // 会影响z
//
//	// 权限的放大
//	// m是只读，而n变成m的别名后，权限就是可读可写的了
//	const int m = 0;
//	// int& n = m; // err
//	const int& n = m; // right
//
//	// 权限的平移和缩小是可以的
//
//	return 0;
//}

//int main()
//{
//	int x = 0;
//	const int m = 0;
//	const int& n = m;
//
//	int p = m; // right，赋值，其修改不影响m
//
//	const int* p1 = &m;
//	// int* p2 = p1; // err，权限放大
//
//	int* p3 = &x;
//	const int* p4 = p3; // right，权限缩小
//
//	return 0;
//}







